/*
 * Copyright (c) 2010, GPU group, BTLab, SJTU.
 * All rights reserved.
 *
 * Filename: PTXTranslator.h
 * Abstract: Head file of PTXTranslator.cpp.
 *
 * Current version: 1.0
 * Programmer: Dylan Dong
 * Data: 2010-01-24
 *
 * Replace version: 1.1
 * Programmer: Dylan Dong
 * Data: 2010-03-12
 * PS: Add supportion of FFT
 */

#ifndef PTXTRANSLATOR_H
#define PTXTRANSLATOR_H

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <assert.h>
#include <algorithm>
#include "g_crossbit/Record.h"
#include "crossbit/VInst.h"

using namespace std;
using namespace crossbit;

namespace g_crossbit
{
// Condition Code
enum CC
{
	noncc,
	eq,
	ne,
	lt_u32,
	lt_s32,
	le,
	gt,
	ge
};

class GVInst
{
	public:
		GVInst(const list<string> &line_of_gvinst);
		GVInst() {}
		~GVInst() {}

		inline Opcode GetOpcode() const { return m_op; }
		inline DataType GetSType() const { return m_stype; }
		inline DataType GetDType() const { return m_dtype; }
		inline CC GetCC() const { return m_con_code; }
		inline string GetSoperand1() const { return m_soperand1; }
		inline string GetSoperand2() const { return m_soperand2; }
		inline string GetDoperand() const { return m_doperand; }

		static int GVInstNum() { return s_gvinst_num; }
		static void IncGVInstNum() { s_gvinst_num++; }

	private:
		Opcode m_op;
		DataType m_stype;
		DataType m_dtype;
		CC  m_con_code;
		string m_soperand1;
		string m_soperand2;
		string m_doperand;
		static int s_gvinst_num;
};

class PTXTranslator{
	public:
		PTXTranslator():m_rh_count(0), m_r_count(0), m_rd_count(0), m_f_count(0), 
						m_fd_count(0), m_p_count(0), m_loop_count(0)
			{
				m_tempfile = "ptx.temp";
			}
		~PTXTranslator() {}
		void TransEngine(Record *records_ptr, const string &infile, const string &outfile);
		void Encode(const list<string> &line_of_gvinst);

	private:
		string m_tempfile;
		int m_reg_init_pos;
		vector<int>m_entry_pos;
		int m_rh_count, m_r_count, m_rd_count, m_f_count, 
			m_fd_count, m_p_count, m_loop_count;
		map<string, string> m_reg_table;
		map<string, string> m_reg_table_64;
		map<string, string> m_addr_loop_label;
		vector<string>m_entry_loop;
		
		void MapTraversal(const string &t_file, const map<string, string> &table);

		int SetRegs(const GVInst &gvinst, string &dreg, string &sreg);
		int SetRegs(const GVInst &gvinst, string &dreg, vector<string> &sreg);
		int SetLoops(const GVInst &gvinst, string &loop_label);
		
		void EncodeMOV(const GVInst &gvinst);
		void EncodeLI(const GVInst &gvinst);
		void EncodeLD(const GVInst &gvinst);
		void EncodeST(const GVInst &gvinst);
		void EncodeADD(const GVInst &gvinst);
		void EncodeADDI(const GVInst &gvinst);
		void EncodeSUB(const GVInst &gvinst);
		void EncodeSUBI(const GVInst &gvinst);
		void EncodeAND(const GVInst &gvinst);
		void EncodeMUL(const GVInst &gvinst);
		void EncodeSLL(const GVInst &gvinst);
		void EncodeCONV(const GVInst &gvinst);
		void EncodeCMP(const GVInst &gvinst);
		void EncodeBRANCH(const GVInst &gvinst);
		void EncodeENTRY(const GVInst &gvinst);
		void EncodeNEXT(const GVInst &gvinst);
		void EncodeERR();

		int PTXInit(Record *record_ptr);
		int RegInit(const string &outfile);
		int PTXOut(const string &outfile);

		string int2str(int &i)
		{
			string s;
			stringstream ss(s);
			ss << i;
			return ss.str();
		}

		string & replace_all(string &str, const string & old_value, const string& new_value)
		{
			while (1)
				{
					string::size_type pos(0);
					if((pos = str.find(old_value)) != string::npos)
						str.replace(pos, old_value.length(), new_value);
					else
						break;
				}
			return str;
		}	
};

}

#endif
